#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include <pthread.h>

#include <unistd.h>
#include <string.h>

#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <errno.h>
#include <signal.h>

#define FILE_DIR "/home/disen/files"
#define CMD_LS "ls"
#define CMD_DEL "del"
#define CMD_NEW "new"
#define CMD_APPEND "append"
#define CMD_UPDATE "update"

#define TMP_FILE "tmp.txt"

int sockfd; // 网络域的套接字

void parse_cmd(char *cmd, char *ret){
    printf("%lu recv cmd %s\n", pthread_self(), cmd);
    
    char filecmd[512] = "";
    if(strncmp(CMD_LS, cmd, strlen(CMD_LS)) == 0){
        sprintf(filecmd, "ls %s > %s", FILE_DIR, TMP_FILE);
        system(filecmd);
        int retfd = open(TMP_FILE, O_RDONLY);
        read(retfd, ret, 512);
        close(retfd);
    }else if(strncmp(CMD_DEL, cmd, strlen(CMD_DEL)) == 0){
        char *del_filename= cmd+strlen(CMD_DEL)+1;
        char path[128] = "";
        sprintf(path, "%s/%s", FILE_DIR, del_filename);
        struct stat s;
        if(stat(path, &s) == 0){  // 验证删除文件是否存在
            sprintf(filecmd, "rm -f %s", path);
            system(filecmd);
            strncpy(ret, "OK", 2);
        }else{
            strncpy(ret, "File Not Found!", strlen("File Not Found!"));
        }
    }else if(strncmp(CMD_NEW, cmd, strlen(CMD_NEW)) == 0){
        char *new_filename= cmd+strlen(CMD_NEW)+1;
        sprintf(filecmd, "touch %s/%s", FILE_DIR, new_filename);
        system(filecmd);
        strncpy(ret, "OK", 2);
    }else if(strncmp(CMD_APPEND, cmd, strlen(CMD_APPEND)) == 0){ 
        strtok(cmd, " ");
        char *filename = strtok(NULL, " ");
        char *text = strtok(NULL, " ");
        sprintf(filecmd, "echo \"%s\" >>  %s/%s", text, FILE_DIR, filename);
        system(filecmd);
        strncpy(ret, "OK", 2);
    }else if(strncmp(CMD_UPDATE, cmd, strlen(CMD_UPDATE)) == 0){ 
        strtok(cmd, " ");
        char *filename = strtok(NULL, " ");
        char *text = strtok(NULL, " ");
        sprintf(filecmd, "echo \"%s\" >  %s/%s", text, FILE_DIR, filename);
        system(filecmd);
        strncpy(ret, "OK", 2);
    }
  
}

void *client_task(void *arg){  // TCP客户端通信线程
    int client = *((int *)arg);
    char cmd[128] = ""; // 客户端发送的指令
    char ret[512] = "";  // 指令执行的结果
    while(1){
        bzero(cmd, 128);
        bzero(ret, 512); 

        ssize_t len = recv(client, cmd, 128, 0);
        if(len == 0) break;  // 客户端程序主动关闭了

        parse_cmd(cmd, ret);  // 解析并执行命令

        // 将命令执行结果回应给客户端
        send(client, ret, strlen(ret), 0);
    } 
    close(client);
    return NULL;
}

// ./cfd <port>
int main(int argc, char const *argv[])
{
    if(argc != 2) return -1;

    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in bind_addr = {
        .sin_family = AF_INET,
        .sin_port = htons(atoi(argv[1])),
        .sin_addr.s_addr = INADDR_ANY
    };

    // 设置端口号可以重用
    int optval=1;
    setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &optval, 4);
    

    if(bind(sockfd, (struct sockaddr *)&bind_addr, sizeof(bind_addr)) != 0){
        perror("bind");
        return -1;
    }

    listen(sockfd, 10);
    while(1){
        struct sockaddr_in client_addr;
        socklen_t client_addr_len = sizeof(client_addr);
        int client_fd = accept(sockfd, (struct sockaddr *)&client_addr, &client_addr_len);
        
        char ip[16] = "";
        inet_ntop(AF_INET, &client_addr.sin_addr.s_addr, ip, 16);
        printf("%s connected!\n", ip);
        
        pthread_t tid;
        pthread_create(&tid, NULL, client_task, &client_fd);
        sleep(2);
    }
    close(sockfd);
    printf("----exit----\n");
    return 0;
}
